﻿using ExcelUnity.Core;
using ExcelUnity.Exporter;
using NPOI.SS.UserModel;

namespace ExcelUnity.Importer;

public class DefaultExcelImporter : IExcelImporter
{
    public List<T> Import<T>(Stream fileStream) where T : new()
    {
        IWorkbook? workBook = null;
        try
        {
            workBook = WorkbookFactory.Create(fileStream);
            var sheet = workBook.GetSheetAt(0);

            //查找表头,对类属性 与 列索引进行匹配
            var columnProperties = CreateColumnProperties(typeof(T), sheet.GetRow(0));

            var list = new List<T>();
            
            //循环读取每一行
            for (var rowIndex = 1; rowIndex <= sheet.LastRowNum; rowIndex++)
            {
                var row = sheet.GetRow(rowIndex);
                
                if (row.IsEmptyOrNull(0, columnProperties.Count))
                    continue;

                
                var obj = new T();
                //循环类属性
                foreach (var property in columnProperties)
                {
                    //获取单元格的值
                    var value = row.GetCell(property.ColumnIndex).GetValue();
                    
                    //可为空的Nullable泛型获取目标类型
                    var targetType = property.PropertyInfo.IsNullable()
                        ? property.PropertyInfo.PropertyType.GetGenericArguments()[0]
                        : property.PropertyInfo.PropertyType;
                    try
                    {
                        //设置指定对象的属性值
                        property.PropertyInfo.SetValue(obj, CommonHelper.ConvertValueType(value, targetType));
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"数据{property.PropertyInfo.Name}转换异常:{ex.Message}.");
                    }
                }

                list.Add(obj);
            }

            return list;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"导入Excel异常!! {ex.Message}");
            return new List<T>(0);
        }
        finally
        {
            workBook?.Close();
        }
    }

    private static List<ColumnProperty> CreateColumnProperties(Type type, IRow row)
    {
        var columnProperties = type.GetProperties()
            .Select(m => new ColumnProperty(m))
            .ToList();

        var cells = Enumerable.Range(row!.FirstCellNum, row.LastCellNum - row.FirstCellNum)
            .Select(x => new
            {
                Index = x,
                Value = row.GetCell(x).GetValue()
            }).ToList();

        foreach (var t in columnProperties)
        {
            t.ColumnIndex = cells.FirstOrDefault(x => x.Value == t.Name)?.Index ?? 999;
        }

        return columnProperties;
    }
}